import {
  Account,
  AccountService,
  Balance,
  BalanceService,
  BankCard,
  BankCardQuery,
  BankCardService,
  CurrencyCode,
  Topup,
  TopupQuery,
  TopupService,
  Transaction,
  TransactionQuery,
  TransactionService,
  Withdrawal,
  WithdrawalQuery,
  WithdrawalService,
} from "@mallfoundry/finance"
import { PageList } from "@mallfoundry/shared/data"
import * as _ from "lodash"
import { useEffect, useState } from "react"

export function useAccount(accountId?: string) {
  const [loading, setLoading] = useState(false)
  const [account, setAccount] = useState(new Account())

  useEffect(() => {
    if (_.isUndefined(accountId)) {
      return
    }
    setLoading(true)
    AccountService.getAccount(accountId)
      .then(setAccount)
      .finally(() => setLoading(false))
  }, [accountId])

  return { loading, account }
}

export function useBalance(accountId ?: string, currency?: CurrencyCode) {
  const [loading, setLoading] = useState(false)
  const [balance, setBalance] = useState(new Balance())

  useEffect(() => {
    if (_.isUndefined(accountId) || _.isUndefined(currency)) {
      return
    }
    setLoading(true)
    BalanceService
      .getBalance({
        accountId,
        currency,
      })
      .then(setBalance)
      .finally(() => setLoading(false))
  }, [accountId, currency])

  return { loading, balance }
}

interface UseBankCardsOptions {
  page?: number | string
  limit?: number | string
  accountId?: string
}

export function useBankCards(options: UseBankCardsOptions) {
  const { page, limit, accountId } = options
  const [loading, setLoading] = useState(false)
  const [pageCards, setPageCards] = useState<PageList<BankCard>>(PageList.empty())

  function refresh() {
    if (_.isEmpty(accountId)) {
      return
    }
    setLoading(true)
    BankCardService
      .getBankCards(
        new BankCardQuery()
          .toBuilder()
          .page(page).limit(limit)
          .accountId(accountId)
          .build())
      .then(setPageCards)
      .finally(() => setLoading(false))
  }

  useEffect(refresh, [page, limit, accountId])

  return {
    loading,
    refresh,
    ...pageCards,
  }
}

interface UseTopupsOptions {
  page?: number | string
  limit?: number | string
  accountId?: string
  statuses?: string | string[]
  createdTimeStart?: string
  createdTimeEnd?: string
}

export function useTopups(options: UseTopupsOptions) {
  const { page, limit, accountId, statuses, createdTimeStart, createdTimeEnd } = options
  const [loading, setLoading] = useState<boolean>(false)
  const [pageTopups, setPageTopups] = useState<PageList<Topup>>(PageList.empty())

  useEffect(refresh, [page, limit, accountId, statuses, createdTimeStart, createdTimeEnd])

  function refresh() {
    if (_.isUndefined(accountId) || _.isEmpty(accountId)) {
      return
    }
    setLoading(true)
    TopupService
      .getTopups(
        new TopupQuery()
          .toBuilder()
          .page(page).limit(limit)
          .accountId(accountId)
          .statuses(statuses)
          .createdTimeStart(createdTimeStart)
          .createdTimeEnd(createdTimeEnd)
          .build())
      .then(setPageTopups)
      .finally(() => setLoading(false))
  }

  return {
    loading,
    refresh,
    ...pageTopups,
  }
}

interface UseTransactionsOptions {
  page?: string | number
  limit?: string | number
  accountId?: string
  types?: string | string[]
  statuses?: string | string[]
}

export function useTransactions(options: UseTransactionsOptions) {
  const { page, limit, accountId, types, statuses } = options
  const [loading, setLoading] = useState(false)
  const [pageTransactions, setPageTransactions] = useState<PageList<Transaction>>(PageList.empty())

  useEffect(() => {
    if (_.isUndefined(accountId)) {
      return
    }
    setLoading(true)

    TransactionService
      .getTransactions(
        new TransactionQuery()
          .toBuilder()
          .page(page).limit(limit)
          .accountId(accountId)
          .types(types)
          .statuses(statuses)
          .build())
      .then(setPageTransactions)
      .finally(() => setLoading(false))
  }, [page, limit, accountId, types, statuses])

  return {
    loading, ...pageTransactions,
  }
}

interface UseWithdrawalsOptions {
  page?: string | number
  limit?: string | number
  accountId?: string
  statuses?: string | string[]
  appliedTimeStart?: string
  appliedTimeEnd?: string
}

export function useWithdrawals(options: UseWithdrawalsOptions) {
  const { page, limit, accountId, statuses, appliedTimeStart, appliedTimeEnd } = options

  const [loading, setLoading] = useState(false)
  const [pageWithdrawals, setPageWithdrawals] = useState<PageList<Withdrawal>>(PageList.empty())

  function refresh() {
    if (_.isUndefined(accountId) || _.isEmpty(accountId)) {
      return
    }
    setLoading(true)
    WithdrawalService
      .getWithdrawals(
        new WithdrawalQuery()
          .toBuilder()
          .page(page).limit(limit)
          .accountId(accountId).statuses(statuses)
          .appliedTimeStart(appliedTimeStart).appliedTimeEnd(appliedTimeEnd)
          .build())
      .then(setPageWithdrawals)
      .finally(() => setLoading(false))
  }

  useEffect(refresh, [page, limit, accountId, statuses, appliedTimeStart, appliedTimeEnd])
  return {
    loading,
    refresh,
    ...pageWithdrawals,
  }
}

export function useWithdrawal(withdrawalId: string) {
  const [loading, setLoading] = useState(false)
  const [withdrawal, setWithdrawal] = useState(new Withdrawal())

  function refresh() {
    if (_.isEmpty(withdrawalId)) {
      return
    }
    setLoading(true)
    WithdrawalService
      .getWithdrawal(withdrawalId)
      .then(setWithdrawal)
      .finally(() => setLoading(false))
  }

  useEffect(refresh, [withdrawalId])

  return {
    loading,
    refresh,
    withdrawal,
  }
}
